﻿namespace _8_面向对象编程;

internal abstract class Animal
{
    protected int age;
    protected string name;
    public abstract void Eat();
}

internal class Dog : Animal
{
    public Dog(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public override void Eat()
    {
        Console.WriteLine($"A dog named {name} eat");
    }
}

internal class Cat : Animal
{
    public Cat(int age)
    {
        this.age = age;
    }

    public override void Eat()
    {
        Console.WriteLine($"Cat's age is {age}");
    }
}

internal class ColorShallow
{
    public int b;
    public int g;
    public int r;

    public ColorShallow(int r, int g, int b)
    {
        this.r = r;
        this.g = g;
        this.b = b;
    }

    public override string ToString()
    {
        return $"{r},{g},{b}";
    }
}

internal class ColorDeep : ICloneable
{
    public int b;
    public int g;
    public int r;

    public ColorDeep(int r, int g, int b)
    {
        this.r = r;
        this.g = g;
        this.b = b;
    }


    public object Clone()
    {
        return new ColorDeep(r, g, b);
    }

    public override string ToString()
    {
        return $"{r},{g},{b}";
    }
}

internal class MyObject : ICloneable
{
    public ColorDeep colorDeep;
    public ColorShallow colorShallow;
    public int id;
    public string size;

    public MyObject(int id, string size, ColorShallow colorShallow, ColorDeep colorDeep)
    {
        this.id = id;
        this.size = size;
        this.colorShallow = colorShallow;
        this.colorDeep = colorDeep;
    }

    public object Clone()
    {
        return new MyObject(id, size, colorShallow, (ColorDeep)colorDeep.Clone());
    }

    public override string ToString()
    {
        return $"id:{id}, size:{size}, colorShallow:{colorShallow}, colorDeep:{colorDeep}";
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        #region 1_接口 + 多借口继承,没啥可说的, 使用起来和Java一模一样, 就是声明的时候还是和继承一样, 使用 : 接口名

        //2_抽象类,抽象类不能实例化,只能继承, 抽象类可以有构造函数, 抽象类可以有属性, 抽象类可以有方法, 抽象类可以有构造函数, 抽象类可以有属性, 抽象类可以有方法

        #endregion

        #region 2_多态

        //Animal[] animals = new Animal[2]; 
        //animals[0] = new Dog("旺财", 3);
        //animals[1] = new Cat(3);
        //foreach (var item in animals)
        //{
        //    item.Eat();
        //}

        #endregion

        #region 3_密封类, 不能够被继承

        // 密封类使用sealed关键字修饰
        // 密封类不能是抽象类, 这是因为seal关键字修饰的类不能有子类

        #endregion

        #region 4_浅层复制 + 深层复制

        var colorShallow = new ColorShallow(100, 200, 133);
        var colorDeep = new ColorDeep(100, 200, 133);
        var obj = new MyObject(1, "M", colorShallow, colorDeep);
        var obj2 = (MyObject)obj.Clone();

        // 更改克隆对象的成员值不会影响原始对象
        obj2.id += 1;
        obj2.size = "L";
        // 更改克隆对象中的引用类型成员值会影响原始对象, 换句话说, 两个对象引用了内存中的同一个对象
        obj2.colorShallow.r += 1;
        // 克隆的深层复制,改变只会改变该对象的成员值引用对象(不是同一个)
        obj2.colorDeep.r += 1;

        Console.WriteLine(obj);
        Console.WriteLine(obj2);

        #endregion

        #region 5_异常

        // try {} catch(Exception e){}, 没啥可说的,可多个catch来捕获多个异常, 和Java一样

        #endregion

        #region 6_未捕获的异常

        // 没有使用try catch捕获的异常, 会抛出异常, 默认会终止程序, 可以使用AppDomain.CurrentDomain.UnhandledException事件来捕获未捕获的异常
        //AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
        //{
        //    Console.WriteLine("UnhandledException");
        //};

        #endregion

        #region 7_自定义异常

        // 自定义异常, 自定义异常需要继承Exception类, 并且构造函数需要传入一个string类型的参数, 这个参数就是异常的描述信息
        //public class MyException : Exception
        //{
        //    public MyException(string message) : base(message)
        //    {
        //    }
        //}

        #endregion
    }
}